#pragma once 

#include <vector>
#include <semaphore.h>
#include <cassert>

const size_t gcap = 5;

template <typename T>
class RingQueue
{

    void P(sem_t& sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0);
        (void)n;
    }

    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;
    }

public:
    RingQueue(const size_t& cap = gcap) : _queue(cap), _capacity(cap)
    {
        int n = sem_init(&_spaceSem, 0, _capacity);
        assert(n == 0);
        n = sem_init(&_dataSem, 0, _capacity);
        assert(n == 0);
        producerStep = comsumerStep = 0;
    }
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
    }

    void push(const T& in_val)
    {
        P(_spaceSem);
        _queue[producerStep++] = in_val;
        producerStep %= _capacity;
        V(_dataSem);
    }

    void pop(T* out_val)
    {
        P(_dataSem);
        *out_val = _queue[comsumerStep++];
        comsumerStep %= _capacity;
        V(_spaceSem);
    }

private:
    std::vector<T> _queue;
    size_t _capacity; // 上限容量
    sem_t _spaceSem; // 空间资源 -- 生产者获取
    sem_t _dataSem; // 数据资源 -- 消费者获取
    int producerStep;
    int comsumerStep;
};